<?php
/***************************************************************
*  Copyright notice
*
*  (c) 2010 Kasper Skårhøj <kaska@llab.dtu.dk>
*  All rights reserved
*
*  This script is part of the TYPO3 project. The TYPO3 project is
*  free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  The GNU General Public License can be found at
*  http://www.gnu.org/copyleft/gpl.html.
*
*  This script is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
 * Plugin 'eNoteServer' for the 'enoteserver' extension.
 *
 * @author	Kasper Skårhøj <kaska@llab.dtu.dk>
 */


require_once(PATH_tslib.'class.tslib_pibase.php');
require_once(t3lib_extMgm::extPath('enoteserver').'class.tx_enoteserver_utils.php');

class tx_enoteserver_pi1 extends tslib_pibase {
	var $prefixId = 'tx_enoteserver_pi1';		// Same as class name
	var $scriptRelPath = 'pi1/class.tx_enoteserver_pi1.php';	// Path to this script relative to the extension dir.
	var $extKey = 'enoteserver';	// The extension key.
	var $expertDebug = TRUE;	// If set, more debug information will hit the poor user of the site/script
	
	var $previewMode = TRUE;	// The plugin supports two modes: preview and live. Each has its separate repository files. From preview files are copied to live when the manager wish. This flag is set by the plugin configuration inside TYPO3.

		// Labels for the eNote types supported. Redundant with those in TCA
	var $eNoteTypeLabels = array(
			0 => 'eNotes',
			1 => 'Exercises',
			2 => 'Quizzes',
			3 => 'Agendas'
		);

	var $eNoteTypeXMLkeys = array(
			0 => 'enote_cfg',
			1 => 'exercise_cfg',
			2 => 'quiz_cfg',
			3 => 'agenda_cfg'
		);

	var $liveLabels	= array(
			0 => '',
			1 => 'Live',
			2 => 'Live(A)',
		);
		
		// Filenames of license icons found in icons/
	var $licenseIcons = array(
			0 => 'C.png',
			1 => 'CC-by.png',
			2 => 'CC-by-nc.png',
			3 => 'CC-by-nd.png',
			4 => 'CC-by-sa.png',
			5 => 'CC-by-nc-nd.png',
			6 => 'CC-by-nc-sa.png',
		);
		
		// Internal: 
	var $books = array();	// The books to which the user has access
	var $collections = array();	// The collections to which the user has access
	var $util;	// Utility object. Common with CLI scripts.
	
	/**
	 * Main method
	 *
	 * @param	string		$content: The content of the PlugIn
	 * @param	array		$conf: The PlugIn Configuration
	 * @return	The content that should be displayed on the website
	 */
	function main($content,$conf)	{
			// Init pi_flexform / plugin configuration.
		$this->pi_initPIflexForm();
		$this->previewMode = ($this->cObj->data['pi_flexform']['data']['sDEF']['lDEF']['liverep']['vDEF'] ? FALSE : TRUE);
		
			// Initialize utility object:
		$this->util = t3lib_div::makeInstance('tx_enoteserver_utils');
		$this->util->piObj = $this;
		$this->util->setPreviewMode($this->previewMode);

			// Generate content:
		if (strstr($this->cObj->currentRecord,'tt_content'))	{
			$conf['pidList'] = $this->cObj->data['pages'];
			$conf['recursive'] = $this->cObj->data['recursive'];
		}
		/*$script .='
			<script language="javascript" type="text/javascript">
			$(document).ready(function(){
				$("div.message-div").effect("highlight", {color: "#ccc"}, 3000);
			});
			</script>
		';*/
		//return $this->pi_wrapInBaseClass('<span style="color:red;">'.($this->previewMode?'PREVIEW':'LIVE').'</span>'.$this->listView($content,$conf));
		if($this->previewMode || $this->piVars['custom']) {
			return $script . $this->pi_wrapInBaseClass($this->listView($content,$conf));
		} else {
			return $this->pi_wrapInBaseClass($this->frontendView($content,$conf));
		}
	}
	function frontendView($content,$conf){
		$this->conf=$conf;		// Setting the TypoScript passed to this function in $this->conf
		$this->pi_setPiVarDefaults();
		$this->pi_loadLL();		// Loading the LOCAL_LANG values
		$this->pi_USER_INT_obj=1;
		
		$this->loadBooks();
		$this->loadCollections($this->previewMode);

		
		if($this->piVars['generate']) {
			$resp = $this->generatePDFCollection($this->piVars['generate']);
			if($resp) {
				$message = $resp;
				$output .= $message;
			}
		}
		$output .='
			<script language="javascript" type="text/javascript">
			function menuOpen(element){
				var open = false;
				$("div.menu-dropdown").each(function(){
					if($(this).hasClass("active")) {
						if(!element){
							open = true;
						} else if(this == element) {
							open = true;
						}
					}
				});
				return open;
			}
			function closeMenu(element) {
				$("div.collection-row").each(function(){
					if(this != element) {
						this.style.border="1px solid transparent";
						this.style.backgroundColor="";
						$(this).css("z-index",0);
						$("div.collection-menu",this).css("visibility", "hidden");
						$("div.menu-dropdown",this).hide().removeClass("active");
					}
				});
			}
			$(document).ready(function(){
					
				$("div.collection-row").mouseenter(function() {
						this.style.border="1px solid #CCC";
						this.style.backgroundColor="#EEE";
						$("div.collection-menu",this).css("visibility","visible");
				}).mouseleave(function(){
					if(!menuOpen(this)){
						closeMenu();
					}
				}).click(function (){
					closeMenu(this);
					$("div.menu-dropdown",this).show().addClass("active");
					$(this).css("z-index",10);
				});
				
				$(document.body).click(function(){
					//alert(menuOpen());
				});
			});
			</script>
		';
		$collection_enote_count = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('count(*) as count, collection, count(DISTINCT book) as bookc, book, MAX(lastchangedrevision'.($this->previewMode?'':'_live').') as revision','tx_enoteserver_note','deleted=0 AND type=0 AND hidden=0','collection');
		foreach($collection_enote_count as $c) {
			$count[$c['collection']] = $c['count'];
			$revision[$c['collection']] = $c['revision'];
			// Does the collection span over multiple books?
			$onebookonly[$c['collection']] = ($c['bookc'] == 1? true : false);
			$book[$c['collection']] = $c['book'];
		}
		$i=0;
		$output .="<h4>eNotebøger</h4>";
		$output .= "<div class='collection-list'>";
		$output .= "<hr class='row-divider' />";
		foreach($this->collections as $colRec) {
			$noteCount = $count[$colRec['uid']];
			$noteRevision = $revision[$colRec['uid']];
			if(!$noteCount || !$onebookonly[$colRec['uid']]) continue; // Do not display empty collections.. or collections spanning over multiple books
			$output .= "<div class='collection-row collection-row-".($i++%2 ? 'odd' : 'even')."'>";
			$output .= "<div class='collection-thumbnail'><img src='".t3lib_extMgm::siteRelPath('enoteserver')."icons/book.png' height='25px'></img></div>";
			$output .= "<div class='collection-title'>" . $colRec['title'] . "</div>";
			$output .= "<div class='collection-menu'></div><div class='menu-dropdown'>";
			$output .= $this->util->setBookConfiguration($this->books[$book[$colRec['uid']]]);
			foreach($this->util->bookConfiguration['enote_cfg']['el'] as $n=>$el)	{
				if ($el['field_compilation'])	{
					$output.=$this->pi_linkTP_keepPIvars(htmlspecialchars($el['field_compilation']['el']['field_title']['vDEF']),Array('generate'=>$colRec['uid'],'compilation_NUM' => $n,'compilation'=>Array($n => Array('defaultBoxEnvironmentList' => htmlspecialchars($el['field_compilation']['el']['field_envlist']['vDEF'])))))."<br/>";
				}
			}
			$output .= "<br/>" . $this->pi_linkTP_keepPIvars('Tilpasset..',Array('collection'=>$colRec['uid'],'book'=>$book[$colRec['uid']],'custom'=>1));
			$output .= "</div>";
			$output .= "<div class='enote-count'>".($noteCount?$noteCount:'0')." eNote".($count[$colRec['uid']]!=1?'r':'')." (rev. ".$noteRevision.")</div>";
			$output .= "</div><hr class='row-divider' />";
			

		}
		$output .= "</div>";
		return $output;
	} 
	
	function generatePDFCollection ($uid,$eNoteType="0") {
		$output = "";
		$enotes = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*','tx_enoteserver_note','collection=' . $uid . ' AND deleted=0 AND type='.$eNoteType . ' AND hidden=0','','enote');
		$note_uids = Array();
		$book_id = $enotes[0]['book'];
		foreach($enotes as $enote) {
			$note_uids[] = $enote['uid'];
			if($enote['book'] != $book_id) {
				return $generation_error;
			}
		}
		$this->util->setBookConfiguration($this->books[$book_id]);
		
		$cfgKey = $this->eNoteTypeXMLkeys[0];
		if (is_array($this->util->bookConfiguration[$cfgKey]['el']))	{
			foreach($this->util->bookConfiguration[$cfgKey]['el'] as $el)	{
				// default is all:
				$boxEnvArray = array_keys($this->util->LaTeX_boxEnvironments);
				$boxEnvArray[] = '_body';

					// Look for input configuration:
				if ($this->piVars['compilation_NUM'] && is_array($this->piVars['compilation'][$this->piVars['compilation_NUM']]))	{
					$compCfg = $this->piVars['compilation'][$this->piVars['compilation_NUM']];
					if (!strstr('ALL',$compCfg['defaultBoxEnvironmentList']))	{
						$boxEnvArray = t3lib_div::trimExplode(',',$compCfg['defaultBoxEnvironmentList']);
					}
					if (is_array($compCfg['optionalBoxEnvironmentList']))	{
						$boxEnvArray=array_merge($boxEnvArray,array_keys($compCfg['optionalBoxEnvironmentList']));	// Add optional
					}
					$boxEnvArray_keys = array_flip($boxEnvArray);
					if (is_array($compCfg['removableBoxEnvironmentList']))	{
						foreach(array_keys($compCfg['removableBoxEnvironmentList']) as $removeKey)	{
							unset($boxEnvArray_keys[$removeKey]);
						}
					}
					$boxEnvArray = array_keys($boxEnvArray_keys);
				}
				if (count($boxEnvArray))	{
					if ($el['field_pdf'] && $el['field_pdf']['el']['field_title']['vDEF'] == "PDF (screen)")	{ //TODO
						$field_preamble = $el['field_pdf']['el']['field_preamble']['vDEF'];
						$field_postamble = $el['field_pdf']['el']['field_postamble']['vDEF'];
						$res = $this->util->createCompositePDF($note_uids,$field_preamble,$field_postamble,'composite',$boxEnvArray,$this->previewMode,'',true,$this->collections[$uid]['title']);
						$localPDF = substr($res['texFile'],0,-4).'.pdf';
						$id = substr(basename($res['texFile']),0,-4);
						/*if(file_exists($localPDF)) {
							if(time() - filemtime($localPDF) > 3) {
							$finalName = basename($this->collections[$uid]['title'].'.pdf');
							header('Content-Type: application/pdf');
							header('Content-Disposition: attachment; filename="'.$finalName.'"');
							header('Content-Length: ' . filesize($localPDF));
							readfile($localPDF);

							exit;
							} else {
								$output .= "<h2>Din eNote genereres</h2>";
								$output .= "<p>Siden opdateres automatisk med 30 sekunders mellemrum</p>";
							}
						} else {
							exec("ls -1rt " . dirname($localPDF) . "/*.ticket | grep -n " . substr(basename($localPDF),0,-4),$r);
							$out = $r[0];
							$match = preg_split("/:/",$out);
							if(file_exists(substr($localPDF,0,-3)."tex")) {
								$output .= "<h2>Din eNote genereres</h2>";
								$output .= "<p>Du er nummer <b>".($match[0]+1)."</b> i køen</b></p>";
							} else {
								$output .= "<h2>Der opstod en fejl</h2>";
								$output .= "<p>Din sammensatte eNote kunne ikke genereres. Kontakt venligst support hvis dette problem vedbliver.</p>";
							}
						}*/
						$output .= $this->ajaxScript($id);
					}
				}
			}
		}				
									
		
		return $output;
		
	}
	function ajaxScript($id) {
		$output = "<div class='message-div'>Indlæser ...</div>";
		$output .= "<script>
		var previousStatus = '';
		var timer = window.setInterval(checkStatus,5000);
		function checkStatus() {
			var id = '".$id."';
			$.get('',{'eID':'tx_enoteserver_ajax','function':'customEnoteStatus','generationID':id},function(e){
				data = jQuery.parseJSON(e);
				if (e != previousStatus) {
					if(data.status.code == 'GENERATING') {
						html = '<h2>Din eNote genereres</h2><p>Vent venligst..</p>';
					} else if(data.status.code == 'QUEUED') {
						html = '<h2>Din eNote genereres</h2><p>Du er nummer <b>'+data.status.position+'</b> i køen</p>';
					} else if(data.status.code == 'DONE') {
						html = '<h2>Din eNote er klar til download</h2><p>Hvis downloaden ikke starter automatisk, klik da <a href=\"'+window.location+'&eID=tx_enoteserver_ajax&function=fetchPDF&generationID='+id+'\">her</a>.</p>';
						window.location = window.location+'&eID=tx_enoteserver_ajax&function=fetchPDF&generationID='+id;
					} else if(data.status.code == 'ERROR') {
						html = '<h2>Der opstod en fejl</h2><p>Din sammensatte eNote kunne ikke genereres. Kontakt venligst support hvis dette problem vedbliver.</p>';
					} else {
						html = '<h2>FEJL</h2>';
					}
					if(data.status.code == 'DONE' || data.status.code == 'ERROR') {
						window.clearTimeout(timer);
					}
					$('div.message-div').html(html);
					$('div.message-div').effect('highlight', {color: '#ccc'}, 1000);
				}
				previousStatus = e;
			},'text');
		}	
		checkStatus();
		</script>";
		return $output;
	}
	/**
	 * Shows a list of database entries
	 *
	 * @param	string		$content: content of the PlugIn
	 * @param	array		$conf: PlugIn Configuration
	 * @return	HTML list of table entries
	 */
	function listView($content,$conf)	{
		$this->conf=$conf;		// Setting the TypoScript passed to this function in $this->conf
		$this->pi_setPiVarDefaults();
		$this->pi_loadLL();		// Loading the LOCAL_LANG values
		$this->pi_USER_INT_obj=1;	// Configuring so caching is not expected. This value means that no cHash params are ever set. We do this, because it's a USER_INT object!
		$lConf = $this->conf['listView.'];	// Local settings for the listView function
	
		if ($this->piVars['show'])	{	// If a single element should be displayed:
			
			$linkParts = explode('-',$this->piVars['show']);
			preg_match('/^NUID([0-9]+)$/',$linkParts[0],$matches);
			
			$this->internal['currentTable'] = 'tx_enoteserver_note';
			$this->internal['currentRow'] = $this->pi_getRecord('tx_enoteserver_note',intval($matches[1]));
		
			if (is_array($this->internal['currentRow']))	{
				$content = $this->singleView($content,$conf,$linkParts);
				return $content;
			} else {
				return 'ERROR: Could not find eNote '.intval($matches[1]);
			}
		} else {
			$fullTable = '';
							// Put the whole list together:
				// Load books:
			$this->loadBooks();

				// Load collections:
			$this->loadCollections($this->previewMode);

				// Perform som actions:
			if ($this->previewMode)	{	// Only do this in preview mode (management) of course:
				if ($this->piVars['action']['svn_update'] && is_array($this->piVars['eNote']))	{
					$log = $this->updateSVN($this->piVars['eNote']);
					$fullTable.='<h2>Log:</h2>'.t3lib_div::view_array($log);
				}
				if ($this->piVars['action']['copy2live'] && is_array($this->piVars['eNote']))	{
					$log = $this->copy2live($this->piVars['eNote']);
					$fullTable.='<h2>Log:</h2>'.t3lib_div::view_array($log);
				}
				if($this->piVars['action']['showLog'] && is_array($this->piVars['eNote'])) {
					$logFiles = $this->getLogFiles($this->piVars['eNote']);
					$fullTable.='<h2>LaTeX Logfiles</h2>';
					foreach($logFiles as $logFile) {
						$fullTable.= '<h3>Logfile for "'.$logFile['rec']['title'].'" with UID '.$logFile['rec']['uid'].'</h3>'.t3lib_div::view_array($logFile['log']);
					}
				}
			}
			
			if ($this->piVars['book'] && isset($this->books[intval($this->piVars['book'])]))	{
				$this->util->setBookConfiguration($this->books[intval($this->piVars['book'])]);

				if ($this->piVars['action']['create_pdf'] || $this->piVars['action']['create_ePub'])	{
				$cfgKey = $this->eNoteTypeXMLkeys[$this->piVars['noteType']];
#debug($cfgKey);
					if (is_array($this->util->bookConfiguration[$cfgKey]['el']))	{
						foreach($this->util->bookConfiguration[$cfgKey]['el'] as $el)	{

								// default is all:
							$boxEnvArray = array_keys($this->util->LaTeX_boxEnvironments);
							$boxEnvArray[] = '_body';
							
								// Look for input configuration:
							if ($this->piVars['compilation_NUM'] && is_array($this->piVars['compilation'][$this->piVars['compilation_NUM']]))	{
								$compCfg = $this->piVars['compilation'][$this->piVars['compilation_NUM']];
								if (!strstr('ALL',$compCfg['defaultBoxEnvironmentList']))	{
									$boxEnvArray = t3lib_div::trimExplode(',',$compCfg['defaultBoxEnvironmentList']);
								}
								if (is_array($compCfg['optionalBoxEnvironmentList']))	{
									$boxEnvArray=array_merge($boxEnvArray,array_keys($compCfg['optionalBoxEnvironmentList']));	// Add optional
								}
								$boxEnvArray_keys = array_flip($boxEnvArray);
								if (is_array($compCfg['removableBoxEnvironmentList']))	{
									foreach(array_keys($compCfg['removableBoxEnvironmentList']) as $removeKey)	{
										unset($boxEnvArray_keys[$removeKey]);
									}
								}
								$boxEnvArray = array_keys($boxEnvArray_keys);
							}
#debug($boxEnvArray);							
#debug($this->piVars);
							if (count($boxEnvArray))	{
								if ($el['field_pdf'] && $this->piVars['action']['create_pdf']==$el['field_pdf']['el']['field_title']['vDEF'])	{
									$field_preamble = $el['field_pdf']['el']['field_preamble']['vDEF'];
									$field_postamble = $el['field_pdf']['el']['field_postamble']['vDEF'];
									$res = $this->util->createCompositePDF(array_keys($this->piVars['eNote']),$field_preamble,$field_postamble,'composite',$boxEnvArray,$this->previewMode,'',true,$this->collections[$this->piVars['collection']]['title'] . " (Tilpasset)");

									$localPDF = substr($res['texFile'],0,-4).'.pdf';
									/*if(file_exists($localPDF)) {
										$finalName = basename('MyENotePDF (UID '.implode(',',array_keys($this->piVars['eNote'])).') (ENV '.implode(',',$boxEnvArray).').pdf');
										header('Content-Type: application/pdf');
										header('Content-Disposition: attachment; filename="'.$finalName.'"');
										header('Content-Length: ' . filesize($localPDF));
										readfile($localPDF);
										
										exit;
									} else {
										$fullTable .= "<h2>Der opstod en fejl</h2>";
										$fullTable .= "<p>Din sammensatte eNote kunne ikke genereres. Kontakt venligst support hvis dette problem vedbliver.</p><br/>";
									}*/
									$output = '';
									/*if(file_exists($localPDF)) {
										if(time() - filemtime($localPDF) > 3) {
										$finalName = "Tilpasset eNote";
										header('Content-Type: application/pdf');
										header('Content-Disposition: attachment; filename="'.$finalName.'"');
										header('Content-Length: ' . filesize($localPDF));
										readfile($localPDF);

										exit;
										} else {
											$output .= "<h2>Din eNote genereres</h2>";
											$output .= "<p>Opdater siden om et par minutter.</p>";
											//$GLOBALS['TSFE']->additionalHeaderData[] = '<meta http-equiv="refresh" content="5">';
										}
									} else {
										exec("ls -1Urt " . dirname($localPDF) . "/*.ticket | grep -n " . substr(basename($localPDF),0,-4),$r);
										$out = $r[0];
										$match = preg_split("/:/",$out);
										if(strlen($out) > 0) {
											$output .= "<h2>Din eNote genereres</h2>";
											$output .= "<p>Du er nummer <b>".($match[0]+1)."</b> i køen</b></p>";
										} else {
											$output .= "<h2>Der opstod en fejl</h2>";
											$output .= "<p>Din sammensatte eNote kunne ikke genereres. Kontakt venligst support hvis dette problem vedbliver.</p>";
										}
									}*/
									/*if(file_exists($localPDF)) {
										if(time() - filemtime($localPDF) > 3) {
										$finalName = basename($this->collections[$uid]['title'].'.pdf');
										header('Content-Type: application/pdf');
										header('Content-Disposition: attachment; filename="'.$finalName.'"');
										header('Content-Length: ' . filesize($localPDF));
										readfile($localPDF);

										exit;
										} else {
											$output .= "<h2>Din eNote genereres</h2>";
											$output .= "<p>Opdater siden om et par minutter.</p>";
											//$GLOBALS['TSFE']->additionalHeaderData[] = '<meta http-equiv="refresh" content="30">';
										}
									} else {
										exec("ls -1Urt " . dirname($localPDF) . "/*.ticket | grep -n " . substr(basename($localPDF),0,-4),$r);
										$out = $r[0];
										$match = preg_split("/:/",$out);
										if(file_exists(substr($localPDF,0,-3)."tex")) {
											$output .= "<h2>Din eNote genereres</h2>";
											$output .= "<p>Du er nummer <b>".($match[0]+1)."</b> i køen</b></p>";
											//$GLOBALS['TSFE']->additionalHeaderData[] = '<meta http-equiv="refresh" content="5">';
										} else {
											$output .= "<h2>Der opstod en fejl</h2>";
											$output .= "<p>Din sammensatte eNote kunne ikke genereres. Kontakt venligst support hvis dette problem vedbliver.</p>";
										}
									}
									$fullTable .= "<div class='message-div'>" . $output . "</div>";*/
									$id = substr(basename($res['texFile']),0,-4);
									$fullTable .= $this->ajaxScript($id);
								}

								if ($el['field_epub'] && $this->piVars['action']['create_ePub']==$el['field_epub']['el']['field_title']['vDEF'])	{
	#								debug($el['field_epub']['el']);
									$res = $this->util->createCompositeEPub(array_keys($this->piVars['eNote']),$el['field_epub']['el']['field_stylesheet']['vDEF'],$boxEnvArray,$this->previewMode);
									if(file_exists($res[0])) {
										$finalName = basename('MyENoteEbook (UID '.implode(',',array_keys($this->piVars['eNote'])).') (ENV '.implode(',',$boxEnvArray).').epub');
										header('Content-Type: application/epub');
										header('Content-Disposition: attachment; filename="'.$finalName.'"');
										header('Content-Length: ' . filesize($res[0]));
										readfile($res[0]);
										echo $res[0];
										exit;
									} else {
										$fullTable .= "<h2>Der opstod en fejl</h2>";
										$fullTable .= "<p>Din sammensatte eBog kunne ikke genereres. Kontakt venligst support hvis dette problem vedbliver.</p><br/>";
									}
								}
							}
						}
					}
					
				}
			}
			


				// Initializing the query parameters:
			$this->internal['results_at_a_time']=t3lib_div::intInRange($lConf['results_at_a_time'],0,1000,100);		// Number of results to show in a listing.
			$this->internal['maxPages']=t3lib_div::intInRange($lConf['maxPages'],0,1000,5);;		// The maximum number of "pages" in the browse-box: "Page 1", "Page 2", etc.
			$this->internal['orderByList'] = 'book,enote,title';
			$this->internal['orderBy'] = $this->internal['orderByList'];
			$addWhere = '';
			
				// Select specific book:
			if ($this->piVars['book'] && isset($this->books[intval($this->piVars['book'])]))	{
				$addWhere.= ' AND book='.intval($this->piVars['book']);
			} else {
				$addWhere.= ' AND book in (0,'.implode(',',array_keys($this->books)).')';
			}
			
				// Select specific collection:
			if ($this->piVars['collection'] && isset($this->collections[intval($this->piVars['collection'])]))	{
				$addWhere.= ' AND collection='.intval($this->piVars['collection']);
			} else {
				$addWhere.= ' AND collection in (0,'.implode(',',array_keys($this->collections)).')';
			}
			
				// Select on previewMode:
			if (!$this->previewMode)	$addWhere.=' AND live>=1';

				// Create book:
			if ($this->piVars['action']['book'] && $this->piVars['book'] && is_array($this->piVars['eNote']))	{
								
				$fullTable .='<h2>Create book of chapters from "'.$this->books[intval($this->piVars['book'])]['title'].'"</h2><form action="'.htmlspecialchars(t3lib_div::getIndpEnv('REQUEST_URI')).'" method="post" style="margin: 0 0 0 0;">';

					// Make listing query, pass query to SQL database:
				$res = $this->pi_exec_query('tx_enoteserver_note',0,'AND type='.intval($this->piVars['noteType']).' '.$addWhere);
				$this->internal['currentTable'] = 'tx_enoteserver_note';
				$fullTable.='<br><div'.$this->pi_classParam('listrow').'>
					<table border="1">
						<tr'.$this->pi_classParam('listrow-header').'>
							<td><p>#</p></td>
							<td><p>Title</p></td>
							<td></td>
						</tr>';
				while($this->internal['currentRow'] = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
					$generationError = unserialize($this->internal['currentRow']['generationError']);
					if ($this->piVars['eNote'][$this->internal['currentRow']['uid']])	{
						if($generationError['PDF'] && $this->previewMode) {
							$fullTable.='<tr>
								<td><p>'.($this->internal['currentRow']['enote']?$this->internal['currentRow']['enote']:'-').'</p></td>
								<td><p>'.htmlspecialchars($this->internal['currentRow']['title']).' </p></td><td><span style="color: red">Omitted: errors in LaTeX</span></td>
							</tr>';
						} else {
							$fullTable.='<tr>
								<td><p>'.($this->internal['currentRow']['enote']?$this->internal['currentRow']['enote']:'-').'<input type="hidden" name="'.$this->prefixId.'[eNote]['.$this->internal['currentRow']['uid'].']" value="1" /></p></td>
								<td><p>'.htmlspecialchars($this->internal['currentRow']['title']).'</p></td><td></td>
							</tr>';
						}
					}
				}
				$fullTable.='</table></div>';
				

				// TODO: Check license, and print license type 
				
				$cfgKey = $this->eNoteTypeXMLkeys[$this->piVars['noteType']];

					// Compilations:
				$setCompilations = FALSE;
				if (is_array($this->util->bookConfiguration[$cfgKey]['el']))	{
					foreach($this->util->bookConfiguration[$cfgKey]['el'] as $n=>$el)	{
						if ($el['field_compilation'])	{

								// Default:
							$fullTable.='<br><input type="radio" name="'.$this->prefixId.'[compilation_NUM]" value="'.$n.'">&nbsp;<b>'.htmlspecialchars($el['field_compilation']['el']['field_title']['vDEF']).'</b> - <em>'.htmlspecialchars($el['field_compilation']['el']['field_description']['vDEF']).'</em><br>';
							$fullTable.='<input type="hidden" name="'.$this->prefixId.'[compilation]['.$n.'][defaultBoxEnvironmentList]" value="'.htmlspecialchars($el['field_compilation']['el']['field_envlist']['vDEF']).'" />';
							
								// Optional:
							if (trim($el['field_compilation']['el']['field_envopt']['vDEF']))	{
								$optionalEnvironments = t3lib_div::trimExplode(',',$el['field_compilation']['el']['field_envopt']['vDEF']);
								$fullTable.='<div style="margin-left: 30px;">Optional sections:';
								foreach($optionalEnvironments as $envKey)	{
									if ($this->util->LaTeX_boxEnvironments[$envKey])	{
										$title = $envKey=='_body' ? 'Bodytext' : $this->util->LaTeX_boxEnvironments[$envKey]['title'];
										$fullTable.='&nbsp;&nbsp;<input type="checkbox" name="'.$this->prefixId.'[compilation]['.$n.'][optionalBoxEnvironmentList]['.htmlspecialchars($envKey).']" value="1" />'.htmlspecialchars($title);
									}
								}
								$fullTable.='</div>';
							}

								// Removable
							if (trim($el['field_compilation']['el']['field_envremove']['vDEF']))	{
								$removableEnvironments = t3lib_div::trimExplode(',',$el['field_compilation']['el']['field_envremove']['vDEF']);
								$fullTable.='<div style="margin-left: 30px;">Removable sections:';
								foreach($removableEnvironments as $envKey)	{
									if ($this->util->LaTeX_boxEnvironments[$envKey])	{
										$title = $envKey=='_body' ? 'Bodytext' : $this->util->LaTeX_boxEnvironments[$envKey]['title'];
										$fullTable.='&nbsp;&nbsp;<input type="checkbox" name="'.$this->prefixId.'[compilation]['.$n.'][removableBoxEnvironmentList]['.htmlspecialchars($envKey).']" value="1" />'.htmlspecialchars($title);
									}
								}
								$fullTable.='</div>';
							}
						}
					}
				}
							


					// Submit buttons:
				$fullTable.='<br><br><input type="submit" name="'.$this->prefixId.'[action][_cancel]" value="Cancel" /> &nbsp; &nbsp; ';
				if (is_array($this->util->bookConfiguration[$cfgKey]['el']))	{
					foreach($this->util->bookConfiguration[$cfgKey]['el'] as $el)	{
						if ($el['field_pdf'])	{
							if ($this->previewMode || !$el['field_pdf']['el']['field_manageronly']['vDEF'])	{
								$fullTable.='<span'.($el['field_pdf']['el']['field_manageronly']['vDEF']?' style="background-color:#ffcccc; padding: 3 3 3 3;"':'').'><input type="submit" name="'.$this->prefixId.'[action][create_pdf]" value="'.htmlspecialchars($el['field_pdf']['el']['field_title']['vDEF']).'" /></span>';
							}
						}
						if ($el['field_epub'])	{
							if ($this->previewMode || !$el['field_epub']['el']['field_manageronly']['vDEF'])	{
								$fullTable.='<input type="submit" name="'.$this->prefixId.'[action][create_ePub]" value="'.htmlspecialchars($el['field_epub']['el']['field_title']['vDEF']).'" />';
							}
						}
					}
				}
				
				$fullTable.='<input type="hidden" name="'.$this->prefixId.'[collection]" value="'.htmlspecialchars($this->piVars['collection']).'" />
							<input type="hidden" name="'.$this->prefixId.'[book]" value="'.htmlspecialchars($this->piVars['book']).'" />
							<input type="hidden" name="'.$this->prefixId.'[noteType]" value="'.htmlspecialchars($this->piVars['noteType']).'" /></form><br/>';
				
			} else {
				
				if($this->previewMode) { // Only show selectors in backend mode
						// Render book selector:
					if (count($this->books)>0)	{
						$fullTable.= '
							<form action="'.htmlspecialchars(t3lib_div::getIndpEnv('REQUEST_URI')).'" method="post" style="margin: 0 0 0 0;">
								<select name="'.$this->prefixId.'[book]" onchange="this.form.submit(); return true;">
									<option value="0" '.(!$this->piVars['book']?' selected="selected"':'').'>Book:</option>
									';
									foreach($this->books as $colRec)	{
										$fullTable.= '<option value="'.$colRec['uid'].'"'.($this->piVars['book']==$colRec['uid']?' selected="selected"':'').'>'.htmlspecialchars($colRec['title']).'</option>';
									}
									$fullTable.= '
								</select>
								<input type="hidden" name="'.$this->prefixId.'[collection]" value="'.htmlspecialchars($this->piVars['collection']).'" />
								</form><br/>';	// Clear var;
					}
				}


				if ($this->piVars['book'] && isset($this->books[intval($this->piVars['book'])]))	{
					if($this->previewMode) { // Only show selectors in backend mode
							// Render collection selector:
						if (count($this->collections)>0)	{
							$fullTable.= '
								<form action="'.htmlspecialchars(t3lib_div::getIndpEnv('REQUEST_URI')).'" method="post" style="margin: 0 0 0 0;">
									<select name="'.$this->prefixId.'[collection]" onchange="this.form.submit(); return true;">
										<option'.(!$this->piVars['collection']?' selected="selected"':'').'>Collection:</option>
										';
										foreach($this->collections as $colRec)	{
											$fullTable.= '<option value="'.$colRec['uid'].'"'.($this->piVars['collection']==$colRec['uid']?' selected="selected"':'').'>'.htmlspecialchars($colRec['title']).'</option>';
										}
										$fullTable.= '
									</select>
									<input type="hidden" name="'.$this->prefixId.'[book]" value="'.htmlspecialchars($this->piVars['book']).'" />
									</form><br/>';	// Clear var;
						}
					}	
						// For each note type, render the list:
						// In live mode, only display eNotes, not exercises and agendas
					for ($a=0; $a<($this->previewMode?4:1); $a++)	{
	
							// Get number of records:
						$res = $this->pi_exec_query('tx_enoteserver_note',1,'AND type='.$a.' '.$addWhere);
						list($this->internal['res_count']) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);

						if ($this->internal['res_count'])	{
							$fullTable .='<form id="notelist_'.$a.'" action="'.htmlspecialchars(t3lib_div::getIndpEnv('REQUEST_URI')).'" method="post" style="margin: 0 0 0 0;">';
								// Make listing query, pass query to SQL database:
							$res = $this->pi_exec_query('tx_enoteserver_note',0,'AND type='.$a.' '.$addWhere);
							$this->internal['currentTable'] = 'tx_enoteserver_note';
	
								// Adds the whole list table
							$fullTable.='<br/><h2>'.$this->eNoteTypeLabels[$a].'</h2>'.$this->pi_list_makelist($res,"notelist_".$a,'style="width:100%"');
					
							$fullTable.='<input type="hidden" name="'.$this->prefixId.'[collection]" value="'.htmlspecialchars($this->piVars['collection']).'" />
										<input type="hidden" name="'.$this->prefixId.'[book]" value="'.htmlspecialchars($this->piVars['book']).'" />
										<input type="hidden" name="'.$this->prefixId.'[noteType]" value="'.htmlspecialchars($a).'" /></form><br/>';
						}
					} 
				} else {
					$fullTable.='Please select a book.';
				}
			
			}
				// Returns the content from the plugin.
			return $fullTable;
		}
	}

	/**
	 * Returns the list of items based on the input SQL result pointer
	 *
	 * @param	pointer		Result pointer to a SQL result which can be traversed.
	 * @param	string		Attributes for the table tag which is wrapped around the table rows containing the list
	 * @return	string		Output HTML, wrapped in <div>-tags with a class attribute
	 * @see pi_list_row(), pi_list_header()
	 */
	function pi_list_makelist($res,$formID,$tableParams='')	{
			// Make list table header:
		$tRows=array();
		$this->internal['currentRow']='';
		$tRows[] = $this->pi_list_header($formID);

			// Make list table rows
		$c=0;
		while($this->internal['currentRow'] = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))	{
			
				// Validate and set file structure:
			$this->internal['currentRow']['dirInfo'] = $this->util->getAbsDirFile($this->internal['currentRow'],$this->previewMode);

				// Only render row with errors in preview mode:
			if (is_array($this->internal['currentRow']['dirInfo']) || $this->previewMode)	{
				$tRows[] = $this->pi_list_row($c);
				$c++;
			}
		}

		$out = '

		<!--
			Record list:
		-->
		<div'.$this->pi_classParam('listrow').'>
			<'.trim('table '.$tableParams).'>
				'.implode('',$tRows).'


				<tr'./*($c%2 ? $this->pi_classParam('listrow-odd') : '').*/'>
						<td valign="top" align="right" colspan="'.($this->previewMode?10:8).'">
							<span style="background-color: #cccccc; padding: 2 2 2 2;">
							';
							if ($this->previewMode)	{
								$out.='<input type="submit" name="'.$this->prefixId.'[action][refresh]" value="Refresh" />';
								$out.='<input type="submit" name="'.$this->prefixId.'[action][svn_status]" value="SVN Info" /> | ';
							}
							$out.='
							With selected:
							'.($this->piVars['book']?'<input type="submit" name="'.$this->prefixId.'[action][book]" value="PDF/ePUB Book" />':'(Select book first!)').'
							';
							if ($this->previewMode)	{
								$out.='	
								<input type="submit" name="'.$this->prefixId.'[action][svn_update]" value="SVN Update" />
								<input type="submit" name="'.$this->prefixId.'[action][copy2live]" value="Copy to Live" />
								<input type="submit" name="'.$this->prefixId.'[action][showLog]" value="Show LaTeX log" /></span>
								';
							}
							$out.='
						</td>
					</tr>				
			</table>
		</div>';

		return $out;
	}

	/**
	 * Returns a formatted revision number
	 *
	 * @param	revision number
	 * @return	A string
	 */

	function pi_rev_date($rev) {
		if($this->getFieldContent('svnauto') == 3) {

			$lengths[] = array("label" => "year", "len" => 60*60*24*365);
			$lengths[] = array("label" => "month", "len" => 60*60*24*30);
			$lengths[] = array("label" => "week", "len" => 60*60*24*7);
			$lengths[] = array("label" => "day", "len" => 60*60*24);
			$lengths[] = array("label" => "hour", "len" => 60*60);
			$lengths[] = array("label" => "minute", "len" => 60);
			$lengths[] = array("label" => "second", "len" => 1);

			// Ignore timestamps older than 20 years
			if(time() - $rev > 60*60*24*365*20)
				return "N/A";

			foreach($lengths as $len) {
				if(($count = floor((time() - $rev) / $len['len'])) >= 1) {
					return $count . "<span title='".date("D, d M Y G:i:s",$rev)."'>&nbsp;" . $len['label'] . ($count > 1 ? 's' : '') . "&nbsp;ago</span>";
				}
			}
		} else {
			return $rev;
		}
	}

	/**
	 * Returns a single table row for list view
	 *
	 * @param	integer		$c: Counter for odd / even behavior
	 * @return	A HTML table row
	 */
	function pi_list_row($c)	{
		$editPanel = $this->pi_getEditPanel();
		if ($editPanel)	$editPanel='<TD>'.$editPanel.'</TD>';
		return '<tr'.($c%2 ? $this->pi_classParam('listrow-odd') : '').'>
				'.($this->previewMode?'<td valign="top"><p>'.$this->getFieldContent('uid').'</p></td>':'').'
				<td valign="top" align="center"><p>'.$this->getFieldContent('enote').'</p></td>
				<td valign="top" style="white-space: nowrap;"><p>'.$this->getFieldContent('title').'</p></td>
				<td valign="top" align="center" style="white-space: nowrap;"><p>'.$this->pi_rev_date($this->getFieldContent('_rev')).'</p></td>
				<td valign="top" style="white-space: nowrap;"><p>'.$this->getFieldContent('book').'</p></td>
				<td valign="top" style="white-space: nowrap;"><p>'.$this->getFieldContent('collection').'</p></td>
				<td valign="top"><p>'.$this->getFieldContent('license').'</p></td>
				<td valign="top" style="white-space: nowrap;"><p>'.$this->getFieldContent('_output').'</p></td>
				'.($this->previewMode?'<td valign="top"><p>'.$this->getFieldContent('live').'</p></td>':'').'
				<td valign="top" align="center"><p>'.$this->getFieldContent('_select').'</p></td>
			</tr>';
	}
	/**
	 * Returns a table row with column names of the table
	 *
	 * @return	A HTML table row
	 */
	function pi_list_header($formID)	{
		return '<tr'.$this->pi_classParam('listrow-header').'>
			'.($this->previewMode?'<td><p>UID</p></td>':'').'
				<td><p>#</p></td>
				<td><p>Title</p></td>
				<td><p>Updated</p></td>
				<td><p>Book</p></td>
				<td><p>Collection</p></td>
				<td><p>License</p></td>
				<td><p>Output</p></td>
				'.($this->previewMode?'<td><p>Live</p></td>':'').'
				<td valign="top" align="center"><p><input type="checkbox" onClick="c=(this.checked?1:0);$(\'#'.$formID.' :input\').each(function(){this.checked=c});"></input></p></td>
			</tr>';
	}
	
	/**
	 * Returns the content of a given field
	 *
	 * @param	string		$fN: name of table field
	 * @return	Value of the field
	 */
	function getFieldContent($fN)	{
		switch($fN) {
			case "title":
				$generationError = unserialize($this->internal['currentRow']['generationError']);
				$detailedError = unserialize($this->internal['currentRow']['detailedError']);
				$error=array();
				if ($this->previewMode && !is_array($this->internal['currentRow']['dirInfo']))	{
					$error[]= htmlspecialchars($this->internal['currentRow']['dirInfo']);
				}
				if ($this->previewMode && $this->internal['currentRow']['live'])	{	// Only in preview mode...
					if (is_array($this->internal['currentRow']['dirInfo']))	{
						$directories = $this->util->getDirectories($this->internal['currentRow']['dirInfo'],$this->internal['currentRow']['uid']);
						if (!is_dir(t3lib_div::getFileAbsFileName($directories['texFromRelDir'])))	{ $error[]= "Error: ".$directories['texFromRelDir']." was not a directory!"; }
						if (!is_dir(t3lib_div::getFileAbsFileName($directories['htmlFromRelDir'])))	{ $error[]= "Error: ".$directories['htmlFromRelDir']." was not a directory!";  }
					}
					if($generationError['PDF']) {
						$error[] = "Error: PDF generation failed (".implode(', ',array_keys($detailedError['PDF'],1)).")";
					}
					if($generationError['HTML']) {
						$error[] = "Error: HTML generation failed (".implode(', ',array_keys($detailedError['HTML'],1)).")";
					}
				}
				if (count($error))	{
					$error = '<span style="font-weight: bold; color: red; font-size: 7pt;"><br>'.implode('<br>',$error).'</span>';
				} else {
					$error = '';
				}
			
					// This will wrap the title in a link.
				return htmlspecialchars($this->internal['currentRow']['title']).$error;
			break;
			case 'enote':
				return $this->internal['currentRow']['enote'] ? $this->internal['currentRow']['enote'] : "-";
			break;
			case '_rev':
				if ($this->internal['currentRow']['svnauto'])	{	// If SVN is enabled:
					if ($this->piVars['action']['svn_status'] && $this->previewMode)	{	// Only if the svn info button is pressed - and we are in preview mode...
						if (is_array($this->internal['currentRow']['dirInfo']))	{
						
								// Running "svn info" on this:
							$cmd = 'svn info "'.$this->internal['currentRow']['dirInfo']['absDir'].'"';
							exec($cmd,$res);
							$svnInfo = $this->util->getSvnInfoAttributes($res);

							$lastChRev = $svnInfo['Last Changed Rev'];
						
								// If last-changed-revision from SVN info doesn't match that stored in the record, we will assume that we need to regenerate the HTML and default PDF file; so we clear the lastgeneratedflag and update revision:
							if ($svnInfo['Last Changed Rev'] > $this->internal['currentRow']['lastchangedrevision'])	{
								$lastChRev = '<span style="color:red">'.$svnInfo['Last Changed Rev'].'!='.$this->internal['currentRow']['lastchangedrevision'].'</span>';
	#							$this->util->clearGenerationFlag($this->internal['currentRow']['uid'], $svnInfo['Last Changed Rev']);
							}
						#	debug($svnInfo);
						}

						return ($this->previewMode?'<span title="'.htmlspecialchars($svnInfo['URL']).'">':'').$lastChRev.' ('.$svnInfo['Revision'].')'.($this->previewMode?'</span>':'');
					} else {
						return $this->internal['currentRow']['lastchangedrevision'.($this->previewMode?'':'_live')].($this->previewMode && $this->internal['currentRow']['svnauto']==2?'(A)':'');
					}
				} else {
					return 'N/A';
				}
			break;
			case 'collection':
				$title = $this->collections[$this->internal['currentRow']['collection']]['title'];
				return htmlspecialchars($title);
			break;
			case 'book':
				$title = $this->books[$this->internal['currentRow']['book']]['title'];
				return htmlspecialchars($title);
			break;
			case 'license':
				$license = $this->collections[$this->internal['currentRow']['collection']]['license'];
				$imgFile = $this->licenseIcons[$license];
	 	 		$img = '<img src="'.t3lib_extMgm::siteRelPath('enoteserver').'icons/'.$imgFile.'" width="60" height="16" />';
				return $img;
			break;
			case '_output':
				if ($this->internal['currentRow']['lastgeneratedflag'])	{
					$outCode='';
					$outCode .= $this->pi_list_linkSingle('HTML','NUID'.$this->internal['currentRow']['uid']);
					$outCode.=' - <a href="'.substr($this->internal['currentRow']['dirInfo']['siteRelDir'].$this->internal['currentRow']['dirInfo']['relFile'],0,-4).'.pdf">PDF</a>';

					return $outCode;
				} else {
					return 'Generating...';
				}
			break;
			case 'live':
				return $this->liveLabels[$this->internal['currentRow']['live']].($this->internal['currentRow']['live'] && $this->internal['currentRow']['lastchangedrevision_live']<$this->internal['currentRow']['lastchangedrevision'] ? '&nbsp;(<span style="color:red;">'.$this->pi_rev_date($this->internal['currentRow']['lastchangedrevision_live']).'</span>)' : '');
			break;
			case '_select':
				return '<input type="checkbox" name="'.$this->prefixId.'[eNote]['.$this->internal['currentRow']['uid'].']" '.($this->piVars['eNote'][$this->internal['currentRow']['uid']]?' checked="checked"':'').'\>';
			break;	
			default:
				return $this->internal['currentRow'][$fN];
			break;
		}
	}
	
	
	
	
	
	
	
	
	
	
	/**
	 * Returns the label for a fieldname from local language array
	 *
	 * @param	[type]		$fN: ...
	 * @return	[type]		...
	 */
	function getFieldHeader($fN)	{
		switch($fN) {
			case "title":
				return $this->pi_getLL('listFieldHeader_title','<em>title</em>');
			break;
			default:
				return $this->pi_getLL('listFieldHeader_'.$fN,'['.$fN.']');
			break;
		}
	}
	
	/**
	 * Returns a sorting link for a column header
	 *
	 * @param	string		$fN: Fieldname
	 * @return	The fieldlabel wrapped in link that contains sorting vars
	 */
	function getFieldHeader_sortLink($fN)	{
		return $this->pi_linkTP_keepPIvars($this->getFieldHeader($fN),array('sort'=>$fN.':'.($this->internal['descFlag']?0:1)));
	}
	
	
	
    function labelNumberValue($NUID)        {
            $linkParts = explode('-',$NUID);
            if (!isset($this->cacheLabels[$linkParts[0]]))  {

                    preg_match('/^NUID([0-9]+)$/',$linkParts[0],$matches);

                    $data = unserialize(t3lib_div::getUrl(t3lib_div::getFileAbsFileName($this->util->enoteHTMLpath.$this->internal['currentRow']['uid']).'/index.html.ser'));
                    $this->cacheLabels[$linkParts[0]]=array();
                    foreach($data['structure']['documentParts'] as $theIdx => $part)        {
                            $this->cacheLabels[$linkParts[0]] = t3lib_div::array_merge($this->cacheLabels[$linkParts[0]],$part['labelsInside']);
                    }
            }
            return $this->cacheLabels[$linkParts[0]][$NUID];
    }
	

	/**
	 * Display a single item from the database
	 *
	 * @param	string		$content: The PlugIn content
	 * @param	array		$conf: The PlugIn configuration
	 * @return	HTML of a single database entry
	 */
	function singleView($content,$conf,$linkParts)	{
		$this->conf = $conf;
		$this->pi_setPiVarDefaults();
		$this->pi_loadLL();
		$this->pi_USER_INT_obj = 1;	// Configuring so caching is not expected. This value means that no cHash params are ever set. We do this, because it's a USER_INT object!

		$content =
		'<div'.$this->pi_classParam('singleView').'>
			<p>eNote: '.$this->getFieldContent('title').'</p>';

		$dirInfo = $this->util->getAbsDirFile($this->internal['currentRow'],$this->previewMode);
		if (is_array($dirInfo))	{

			$htmlParser = t3lib_div::makeInstance('t3lib_parsehtml');	


				// ENTEN:
#			$structure = $this->util->latexmlOutput2HTMLStruct_eNote($dirInfo,$this->internal['currentRow']['uid']);		// TODO: Cache this...

				// ELLER:
			$serContent = unserialize(t3lib_div::getUrl(t3lib_div::getFileAbsFileName($this->util->enoteHTMLpath.$this->internal['currentRow']['uid']).'/index.html.ser'));
			$structure = $serContent['structure'];


			
			
			
			$structure = $this->filterStructure($structure,$linkParts);

			$accum = $this->accumulateStructure($structure);

#debug($linkParts);



				// Navigation:
			$content.= '<hr><p>';
			$content.= $this->pi_list_linkSingle($this->pi_getLL('back','Up'));
			if (isset($structure['_previousIDX'])) $content.= ' | '.$this->pi_list_linkSingle('< PREV','NUID'.$this->internal['currentRow']['uid'].'-IDX'.$structure['_previousIDX']);
			if (isset($structure['_nextIDX'])) $content.= ' | '.$this->pi_list_linkSingle('NEXT >','NUID'.$this->internal['currentRow']['uid'].'-IDX'.$structure['_nextIDX']);
			$content.= '</p><hr>';

			if (is_array($structure))	{

				$tableRows=array();
				// Set appropriate page title
				if($this->internal['currentRow']['type'] == 0) {
					if($structure['documentParts'][0] || $structure['documentParts'][1]) {
						$GLOBALS['TSFE']->page['title'] = 'eNote ' . $this->internal['currentRow']['enote'] . ': ' . $this->internal['currentRow']['title'];
					} else {
						$firstPart = reset($structure['documentParts']);
						$doc = new DOMDocument();
					  	$doc->strictErrorChecking = FALSE;
					  	$doc->loadHTML($firstPart['HTML']);
					  	$html = simplexml_import_dom($doc);
						//$html = new SimpleXMLElement($firstPart['HTML']);
						$title = array_shift($html->xpath("//*[name()='h1' or name()='h2' or name()='h3']"));
						if(!$title) {
							$title = '';
						}
						$GLOBALS['TSFE']->page['title'] = $title;
					}
				} else {
					//$GLOBALS['TSFE']->page['title'] = $this->eNoteTypeNames[$data['eNoteRec']['type']];
				}
				
				if($this->internal['currentRow']['enote']) {
					$content = '<div class="enote-header"><div class="box-title-lines"><div>&nbsp;</div></div>eNote '.$this->internal['currentRow']['enote'] . '</h1></div>';
				}

				foreach($structure['documentParts'] as $theIdx => $part)        {
					/*if(isset($part['HeaderLevel']) && $part['HeaderLevel'] == 0 && $data['eNoteRec']['enote']) {
						$content = '<div class="enote-header"><div class="box-title-lines"><div>&nbsp;</div></div>eNote '.$data['eNoteRec']['enote'] . '</h1></div>';
					}*/
                    $HTML = $part['HTML'];
					if(!trim($HTML)) {
						continue;
					}
                    // Prefixing relative paths:
                    $HTML = $htmlParser->prefixResourcePath($this->util->enoteHTMLpath.$this->internal['currentRow']['uid'].'/',$HTML);
                    $HTML = str_replace('###NOTICE_ENV_ICON_PATH###','typo3conf/ext/enoteserver/icons/note/',$HTML);
                    $HTML = preg_replace('/Chapter \d+\./','',$HTML);               // TEMPORARY!!!

                            // Processing A-tag for all links to IDs internally for this enote. Any links to other enotes are processed differently.:
                    $blocks = $htmlParser->splitIntoBlock('a',$HTML);
                    foreach($blocks as $k => $value){
                            if (intval($k)%2)       {
                                    
                                            // Page links:
                                    $matches = array();
                                    preg_match('/href="\#([^"]+)"/' ,$value , $matches);
                                    if (count($matches))    {
                                            if (!in_array($matches[1],$accum['idsInside'])) {       // Is external...:
                                                    $IDX = $structure['idIndex'][$matches[1]];
                                                    $blocks[$k] = $this->pi_list_linkSingle(strip_tags($value),$linkParts[0].'-'.($IDX?'IDX'.$IDX:''),1);
#                                                                       debug(array($value,$blocks[$k],$matches,$IDX),'BEFORE-AFTER');
                                            } else {
                                                    $blocks[$k] = '<a href="'.t3lib_div::getIndpEnv('REQUEST_URI').'#'.$matches[1].'">'.strip_tags($value).'</a>';
                                            }
                                    }
                                    
                                    if (!count($matches))   {
                                                    // External links:
                                            $matches = array();
                                            preg_match('/href="(tref|thref|refA|hrefA|trefA|threfA)::([^"]+)"/' ,$value , $matches);
                                            if (count($matches))    {

                                                            // Create links with internal references:
                                                    if (t3lib_div::inList('tref,thref,refA,trefA,threfA',$matches[1]))      {
                                                            if (t3lib_div::inList('tref,refA,trefA',$matches[1]))   {
                                                                    $value=strip_tags($value).' '.$this->labelNumberValue($matches[2]);
                                                            }
                                                            $theLink =$this->pi_list_linkSingle(strip_tags($value),$matches[2],1);
                                                            $theURL = $this->cObj->lastTypoLinkUrl;
                                                    } else {
                                                            $theLink =      '<a href="'.htmlspecialchars($matches[2]).'">'.strip_tags($value).'</a>';
                                                            $theURL = $matches[2];
                                                    }

                                                    /*if (t3lib_div::inList('refA,hrefA,trefA,threfA',$matches[1]) && $GLOBALS['TSFE']->loginUser)    {
                                                            $ELOinfo = $this->getELAtom($theURL);
                                                            $blocks[$k] = '<span style="'.($ELOinfo['userdata'][0]['done']?'':'border: solid #bbbbbb 1px;').' background-color: '.($ELOinfo['userdata'][0]['done']?'transparent':'#ffff99').';">'.
                                                                            '<img src="typo3conf/ext/enoteserver/icons/done'.(!$ELOinfo['userdata'][0]['done']?'_d':'').'.png" width="20" height="24" align="absmiddle"/>'.
                                                                            ($ELOinfo['userdata'][0]['fav']?'<img src="typo3conf/ext/enoteserver/icons/heart.png" width="12" height="12" align="absmiddle" />&nbsp;':'').
                                                                            $this->pi_linkTP(strip_tags($theLink),Array($this->prefixId=>array('atom'=>$ELOinfo['uid'],'returnUrl'=>t3lib_div::getIndpEnv('REQUEST_URI'))),1).
                                                                            '</span>';
                                                    } else {*/
                                                            $blocks[$k] = $theLink;
                                                    //}
                                                    
                                            #       debug(array($value,$blocks[$k],$matches,$IDX,$theLink),'BEFORE-AFTER');
                                            }
                                    }
                            }
                    }
                    
                    $HTML = implode('',$blocks);	
					

					$HTMLcode = $this->expertDebug ? '<td valign="top"><pre style="font-size:8pt;">'.htmlspecialchars($HTML).'</pre></td>' : '';

					if ($this->expertDebug)	{
						$mgmInfo = 'Index: '.$theIdx.t3lib_div::view_array(array_merge($part,array('HTML'=>'')));
					} else {
						$theLabels = array();
						foreach($part['labelsInside'] as $labelKey => $labelValue)	{
							if ($part['toplabel']===$labelKey)	{
								$theLabels[]='<b>'.htmlspecialchars($labelKey).'</b> : <em>'.$labelValue.'</em>';
							} else {
								$theLabels[]=htmlspecialchars($labelKey).' : <em>'.$labelValue.'</em>';
							}
						}
						$mgmInfo = implode('<br>',$theLabels);
					}

					unset($part['HTML']);
					if ($this->previewMode)	{
						$tableRows[] = '
							<tr>
								<td valign="top">'.$mgmInfo.'</td>
								<td valign="top"><div class="enoteHTML">'.$HTML.'</div></td>
								'.$HTMLcode.'
							</tr>';
					} else {
						$tableRows[] = '
							<tr>
								<td valign="top"><div class="enoteHTML">'.$HTML.'</div></td>
							</tr>';
					}
				}
				if ($this->previewMode)	{
					$content.='<table border="1" style="border: 1px solid #cccccc">'.implode('',$tableRows).'</table>';
				} else {
					$content.='<table>'.implode('',$tableRows).'</table>';
				}
			} else $content.=$structure;
		}
		
		$content.= '</div>';
		
		return $content;
	}	
	
	function pi_list_linkSingle($str,$id='')	{
		if ($this->prefixId)	{
			$overrulePIvars=array('show'=>$id?$id:'');
			$str = $this->pi_linkTP_keepPIvars($str,$overrulePIvars);
		}
		return $str;
	}	
	
    function filterStructure($structure,$linkParts) {

            if (!$linkParts[1])     return $structure;      // If nothing but "NUID[UID]" is passed, all is to be shown

            if (is_array($structure['documentParts']))      {
                    $newStructure = array();
                    $inside = FALSE;
                    $headerLevel = 0;
#debug($structure['documentParts']);

                    // Traverse structure:
            foreach($structure['documentParts'] as $theIdx => $part)        {
                    if ($inside)    {
                                    // ... or if no ending label is given, look for the next section on the same HeaderLevel:
                            if (!$linkParts[2] && (($part['HeaderLevel'] && $part['HeaderLevel'] <= $headerLevel) || !isset($headerLevel)))      {
                                    break;
                            }
                    }
                            // Looking for the "start":
                    if (!$inside && $linkParts[1] && (in_array($linkParts[0].'-'.$linkParts[1],array_keys($part['labelsInside'])) || 'IDX'.$theIdx==$linkParts[1])) {
                            $inside = TRUE; // Indicates, that we are now accumulating content - we are "inside" the linked section.
							$headerLevel = $part['HeaderLevel'];
                    }

                    if ($inside)    {
                                    // If "inside", add the section:
                            $newStructure[$theIdx] = $part;

                                    // If only one section is to be shown, we break here.
                            if (isset($linkParts[2]) && !trim($linkParts[2]))       break;  

                                    // ... otherwise, look for the ending label if given:
                            if ($linkParts[2] && (in_array($linkParts[0].'-'.$linkParts[2],array_keys($part['labelsInside'])) || 'IDX'.$theIdx==$linkParts[2]))     {
                                    break;
                            }
                            
                    } else {
                            $structure['_previousIDX'] = $theIdx;
                    }
            }
            $structure['_nextIDX'] = key($structure['documentParts']);
            if (!$structure['_nextIDX'])    unset($structure['_nextIDX']);

            $subtract = t3lib_div::intInRange($linkParts[3],0,10);
            if ($subtract)  {
                    for ($a=0;$a<$subtract;$a++)    {
                            array_pop($newStructure);
                    }
            }
            $structure['documentParts'] = $newStructure;
            return $structure;
            }
    }
	
	function accumulateStructure($structure)	{
		$accum = array('labelsInside'=>array(),'idsInside'=>array());

		foreach($structure['documentParts'] as $theIdx => $part)	{
			$accum['labelsInside'] = t3lib_div::array_merge($accum['labelsInside'],$part['labelsInside']);
			#$accum['HTML'].= $part['HTML'];
			$accum['idsInside'] = array_merge($accum['idsInside'],$part['idsInside']);
		}
		return $accum;
	}
	
	/**
	 * Loads the collections the user has access to:
	 *
	 * @return	void
	 */
	function loadCollections($previewMode)	{
		$pidList = $this->pi_getPidList($this->conf['pidList'],$this->conf['recursive']);
		$collections = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*','tx_enoteserver_collection','pid IN ('.$pidList.')'.$this->cObj->enableFields('tx_enoteserver_collection'),'','title','','uid');
		if($this->previewMode) {
			foreach($collections as $id => $collection) {
				if(!in_array(intval($GLOBALS['TSFE']->fe_user->user['uid']),explode(",",$collection['managers']))) {
					unset($collections[$id]);
				}
			}
		}
		$this->collections = $collections;
	}
	
	/**
	 * Loads the available books
	 *
	 * @return	void
	 */
	function loadBooks()	{
		$pidList = $this->pi_getPidList($this->conf['pidList'],$this->conf['recursive']);
		$this->books = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*','tx_enoteserver_book','pid IN ('.$pidList.')'.$this->cObj->enableFields('tx_enoteserver_book'),'','title','','uid');
	}
	
	function updateSVN($eNotes)	{
		$log = array();
		foreach($eNotes as $uid => $flag)	{
			$rec = $this->pi_getRecord('tx_enoteserver_note',$uid);
			$log[$rec['uid']] = $this->util->updateSVN($rec);
		}
		
		return $log;
	}

	function copy2live($eNotes)	{
		$log = array();
		foreach($eNotes as $uid => $flag)	{
			$rec = $this->pi_getRecord('tx_enoteserver_note',$uid);
			if ($rec['live'])	{
				$log[$rec['uid']] = $this->util->copy2live($rec);
			} else {
				$log[$rec['uid']] = 'This eNote is not configured to be in Live!';
			}
		}
		
		return $log;
	}
	
	function getLogFiles($eNotes) {
		$en = array();
		foreach($eNotes as $uid => $flag) {
			$rec = $this->pi_getRecord('tx_enoteserver_note',$uid);
			$en[] = array('log'=>unserialize($rec['lastLog']), 'rec' => $rec);
		}
		return $en;
	}
}



if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/enoteserver/pi1/class.tx_enoteserver_pi1.php']){
	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/enoteserver/pi1/class.tx_enoteserver_pi1.php']);
}

?>
